#include<stdio.h>
#include<string.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include "HctpApi.h"
#include "HctpType.h"

void onSuccess(S32 netType) {
    printf("NetType=%d \n", netType);
}

void onFail(S32 errCode) {
    printf("ErrCode=%d \n", errCode);
}

void onProgressLocal(void *context, U64 progress, U64 total) {
    printf("progress=%ld \n", progress);
}

//本例子中使用全局变量，handle支持多实例，
// 建议集成时候实现包装类如 HctpWrapper，将handle作为其类成员

#define  MAX_LINE  1024

U64 handle = -1;

BOOL returnCodeNeedRetry(S32 ret) {
    if ((HCTP_RET_ERROR_PPCS_BROKEN == ret)
        || (HCTP_RET_ERROR_DATATRANS_MD5 == ret))
        return true;
    return false;
}

//初始化API
// 使用设备的DID（海美迪云存宝的）请求下面2个参数
//initStr -- 尚云初始化字符串
//didStr -- 设备端的尚云did（注意 与设备的DID不同）， 测试代码是临时测试用的机器的
// connectMode--连接模式（可以使用0x7A）
void hctpWrapperInit(const char *initStr, const char *didStr, U32 connectMode) {
    S8 sTunnelParam[MAX_LINE];

    if (initStr == NULL || didStr == NULL) {
        printf("Parameter Error In hctpWrappeInit()!\n");
        return;
    }

    //如果已经初始化了，需要反初始化
    if (handle != -1) {
        hctpDeinit(handle);
        handle = -1;
    }

    //设置Debug级别
    hctpSetLogLevel("DBG");  // 默认是ERR， 参数可以为 “DBG”，“INFO”， “WNR”和 “ERR"

    //准备初始化参数
    memset(sTunnelParam, 0, sizeof(sTunnelParam));
    snprintf(sTunnelParam, MAX_LINE - 1, "PPCS %s %s %x", initStr, didStr, connectMode);

    printf(" TunnelParam: %s \n", sTunnelParam);
    // 调用dll库的初始化API
    handle = hctpInit((S8 *) &sTunnelParam);

    //错误处理，小于等于0 错误
    if (handle <= 0) {
        printf("hctpWrappeInit() handle =%ld Error !\n", handle);
        handle = -1;
    }
    //注意： 不同平台这个信号，需要处理SIGPIPE
    //PPCS 库连接后，APP到后台一段时间，Pipe broken会导致APP闪退
    // signal(SIGPIPE, SIG_IGN);
}

//反初始化
void hctpWrapperDeInit() {
    if (handle != -1) {
        hctpDeinit(handle);
        handle = -1;
    }
}

//连接设备，内部分配信道
void hctpWrapperConnect() {
    S32 ret;
    if (handle <= 0) {
        printf("hctpWrapperConnect() handle =%ld Error !\n", handle);
        return;
    }
    // hctpConnect 是异步，需要等待连接成功，或者超时退出
    // 可以设置变量退出下面的循环，如果不想连接了
    do {
        ret = hctpConnect(handle, onSuccess, onFail);
        if (ret != HCTP_RET_OK) {
            sleep(1);
        }
    } while (ret != HCTP_RET_OK);
}

//断开设备，释放信道
void hctpWrapperDisconnect() {
    S32 ret;
    if (handle <= 0) {
        printf("hctpWrapperDisconnect() handle =%ld Error !\n", handle);
        return;
    }
    ret = hctpDisconnect(handle);
    handle = -1;
}

//重要说明 HCTP_RET_ERROR_PPCS_BROKEN，
//                 HCTP_RET_ERROR_DATATRANS_MD5 需要重试下
//   详细参数参见main() 中调用的地方
//

S32 hctpWrapperUploadFile(
        long id,
        const char albumFlag,
        char *md5Str,
        char overwriteFlag,
        char *szLocalFilename,
        char *szRemoteFilename,
        char *szRemotePath,
        char *szJsonString,
        void *context,
        PFOnProgress onProgress
) {
    S32 ret;
    TFileUpload uploadFile;
    if (handle <= 0) {
        printf("hctpWrapperDisconnect() handle =%ld Error !\n", handle);
        return -1;
    }
    //id 必须是唯一值
    uploadFile.id = id;
    uploadFile.albumFlag = albumFlag;
    snprintf(uploadFile.md5String, 63, "%s", md5Str);
    uploadFile.overwriteFlag = overwriteFlag;
    uploadFile.szLocalFilename = szLocalFilename;
    uploadFile.szRemoteFilename = szRemoteFilename;
    uploadFile.szRemotePath = szRemotePath;
    uploadFile.szJsonString = szJsonString;
    //一定要处理错误的返回码
    ret = hctpFileUpload(handle, &uploadFile, context, onProgress);
    if (ret != HCTP_RET_OK) {
        if (returnCodeNeedRetry(ret)) {
            usleep(200000);
            ret = hctpFileUpload(handle, &uploadFile, context, onProgress);
        }
    }
    return ret;
}

//参数参见main（）说明
S32 hctpWrapperDownloadFile(
        long id,
        char *szRemoteFilename,
        char *szLocalFilename,
        char *szJsonString,
        void *context,
        PFOnProgress onProgress
) {
    S32 ret;
    TFileDownload downloadFile;

    if (handle <= 0) {
        printf("hctpWrapperDownloadFile() handle =%ld Error !\n", handle);
        return -1;
    }

    downloadFile.id = id;
    downloadFile.szRemoteFilename = szRemoteFilename;
    downloadFile.szLocalFilename = szLocalFilename;
    downloadFile.szJsonString = szJsonString;

    //一定处理错误吗
    ret = hctpFileDownload(handle, &downloadFile, context, onProgress);
    if (ret != HCTP_RET_OK) {
        if (returnCodeNeedRetry(ret)) {
            usleep(200000);
            ret = hctpFileDownload(handle, &downloadFile, context, onProgress);
        }
    }
    return ret;
}

// 停止任务
//id --上传，下载任务的taskid
/// @param pause  停止任务的模式   pause:  1  , delete 0;
S32 hctpWrapperPauseStopById(long id, U32 pause) {
    S32 ret;
    ret = hctpTransferStopTaskById(handle, id, pause);
    return ret;
}

char *getUploadJson() {
    /**
   * {
"fsize": //上传文件的实际大小
"ctime":1624874639000,   //文件的实际创建时间戳
"mtime":1624874639000, // 文件的实际修改时间戳
"owner":"5f6db6bd23c8ea218b0b8522",  //来自于 API接口 file/list 父目录的owner, 现在代码写死了，需要按需修改
"ftype":"PIC",   //文件类型，依据后缀名识别  可用值：PIC、AUDIO、VIDEO、DOC、OTHER
"md5":"f27241459f0d148795422c00b544a19a", //文件的md5，不是标准的。海美迪的算法
// 调用 auth获取的，30分钟会失效，建议： 服务器返回的过期时间*0.8 后获取
 "token":"eyJ0eXAiOiJKV1QtZCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMzcxMzY5NDEzOSIsImF1ZCI6IjYwYjc1NDAwY2I0MT
ljMGE0ZDYxMzBmMCIsImlkIjoiNWY3ZmJmMzAzY2I0MmQ0NDY0M2FiZmI0Iiwic29hcCI6InVzZXIiLCJjcmVhdGVkIjoxNjU4NzI3OTI1OTE0
LCJleHAiOjE2NTg3Mjk3MjV9.hGhjEvxTXpq9gZsmHIUe99mYVa-txyTWTCJMkUKVFWktO5ieOBk66xF_WAlpcccwSOUhLyjkFpAF9oS0bpcRS
fZgAW8-HNv_LOns6dOxCt_mtBrm04lOg6IkNv5UhGnTgJoQFkvgx03GJ-ggeuOQGe8_WRGc8MYXbnd7Al0aLmcn3cE936apOP0AwUoChOT_fYV
vtvg5fpfibfjy_Mo7Z_eA_e8ZixxpfE1515jyEIzuVAz8g3aSnMHDh7BZSl_pzu1r-Rv77tcwUswckmPyubtGVqHzDk6UZSDzjRSmq11KYK6UH
0oaUZUWFyfmP_h5y8xFJrL-2IYkWphjMuTW8A",
"trumpid":"634f9380d95f0f6c3329c7a3"
}
 */
 //注意:   实际代码中更需要填写 auth 获取的token
    char *json = "{ \"fsize\":146526, \
                               \"ctime\":1624874639000,\
                                \"mtime\":1624874639000,\
                                \"owner\":\"5f73fd4800fb3f336c1b3367\",\
                                 \"ftype\":\"OTHER\",  \
                                  \"md5\":\"9305e2ba903c68397f395fdf11fbdff0\", \
                                  \"token\": \" \"}";
    return json;
}

char *getDownloadJson() {
    /*
    {
               "id": 1,             //taskid
                "user":    "5f7fbf303cb42d44643abfb4",    // App 用户的UID， App login的时候获得的
                "owner":"5f7fbf303cb42d44643abfb4",    // 下载文件的所有者，file/list获取的
                // 调用 auth获取的，30分钟会失效，建议： 服务器返回的过期时间*0.8 后获取
                "token": "eyJ0eXAiOiJKV1QtZCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIxMzcxMzY5NDEzOSIsImF1ZCI6IjYwYjc1NDAwY2I0MTljMGE0ZDYxMzBmMCIsImlkIjoiNWY3ZmJmMzAzY2I0MmQ0NDY0M2FiZmI0Iiwic29hcCI6InVzZXIiLCJjcmVhdGVkIjoxNjU4NzI3OTI1OTE0LCJleHAiOjE2NTg3Mjk3MjV9.hGhjEvxTXpq9gZsmHIUe99mYVa - txyTWTCJMkUKVFWktO5ieOBk66xF_WAlpcccwSOUhLyjkFpAF9oS0bpcRSfZgAW8 - HNv_LOns6dOxCt_mtBrm04lOg6IkNv5UhGnTgJoQFkvgx03GJ - ggeuOQGe8_WRGc8MYXbnd7Al0aLmcn3cE936apOP0AwUoChOT_fYVvtvg5fpfibfjy_Mo7Z_eA_e8ZixxpfE1515jyEIzuVAz8g3aSnMHDh7BZSl_pzu1r - Rv77tcwUswckmPyubtGVqHzDk6UZSDzjRSmq11KYK6UH0o aUZUWFyfmP_h5y8xFJrL - 2 IYkWphjMuTW8A "
    }
    */

    //注意:   实际代码中更需要填写 auth 获取的token
    // devicetype -- phone ,pc
    char *downjson = "{ \"id\":1111,\
                 \"user\":\"5f73fd4800fb3f336c1b336\",\
                  \"owner\":\"5f73fd4800fb3f336c1b3367\",\
                   \"token\":\" \",\
                   \"devicetype\": \"pc\"}";
    return downjson;
}

int main(int argc, char *argv[]) {
    U64 context;

    //PPCS 库连接后，APP到后台一段时间，Pipe broken会导致APP闪退
    signal(SIGPIPE, SIG_IGN);
    TFileUpload upLoadFile;
    TFileDownload downLoad;

    //任务id，每次上传下载都不同，用于区分取消任务等。
    long taskid = 121222222L;

    //以下2个参数，从服务器获取
    const char *ppcsInitStr = "ADCCBGBIKCNICEICAPHNAIEFCNMECDNPHPAJBBGEEAJFLJKNHPEJCDPJDLLCMKKBEENMPBCOKIJIACGFJFMBNEEBJBODAFHBFFDPGMAGJFPKAAHPBAAKKMMIHPMFAN";
    const char *ppcsDid = "CHA-010222-LYMRF";
    //底层连接的默认顺序，可以使用
    const unsigned char connectMode = 0X7A;

    hctpWrapperInit(ppcsInitStr, ppcsDid, connectMode);
    hctpWrapperConnect();

    //这个MD5对于是定制的
    //使用头尾方式计算的。海美迪可以提供算法

    S8 albumFlag = 0;    //default 0,    1文件同时加入照片库
    char *md5Str = "9305e2ba903c68397f395fdf11fbdff0";
    /*
     0x0：   不覆盖模式上传 （如果重复，设备端返还上传请求失败）
     0x01:   通知设备端覆盖上传
     0x02:   通知设备端重命名保存
    */
    char overwriteFlag = 0X02;
    //本地文件名
    char *szRemoteFilename = "test_data.txt";

    //远端文件夹，实际代码使用 file/list 获取的fid
    char *szRemotePath = "/mnt/data/public/sss";

   //参见函数说明
    char *szJsonString = getUploadJson();

    S32 uploadret = hctpWrapperUploadFile(
            taskid,
            albumFlag,
            md5Str,
            overwriteFlag,
            szRemoteFilename,
            szRemoteFilename,
            szRemotePath,
            szJsonString,
            &context,
            onProgressLocal
    );

    printf("hctpWrapperUploadFile ret=%d \n", uploadret);

    taskid++;

    char *szdownLocalFilename = "libhctp1.so;";
    //注意：
   //下面代码是测试，实际代码 需要使用fid（字符串），通过file/list 获取
    char *szdownRemoteFilename = "/mnt/data/public/libhctp1.so";
    char *szdownJsonString = getDownloadJson();

    S32 downret = hctpWrapperDownloadFile(
            taskid,
            szdownRemoteFilename,
            szdownLocalFilename,
            szdownJsonString,
            &context,
            onProgressLocal
    );

    printf("hctpWrapperDownloadFile ret=%d \n", downret);

    hctpWrapperDisconnect();
    hctpWrapperDeInit();

    printf("Done!\n");
    return 1;
}
